#define DEBUG
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using HslControls.Charts;
using HslControls.Charts.Series;

namespace HslControls
{
	/// <summary>
	/// 图表控件，一个支持多坐标轴以及多种数据绘制样式的图表。
	/// </summary>
	public class HslChart : Control
	{
		/// <summary>
		/// 轴间隔(标题与轴的间隔，标签与绘图区的间隔)
		/// </summary>
		public const int AxisMargin = 3;

		/// <summary>
		/// 分割器之间的小网格线条数
		/// </summary>
		public const int MiniGridSum = 5;

		/// <summary>
		/// 鼠标拖动状态
		/// </summary>
		private bool isDraging = false;

		/// <summary>
		/// 标记线位置
		/// </summary>
		private Point markLineLocation;

		/// <summary>
		/// 鼠标拖动位置
		/// </summary>
		private Point dragLocation;

		/// <summary>
		/// 缩放倍数
		/// </summary>
		private double zoomTimes = 0.0;

		/// <summary>
		/// 内容更新标识
		/// </summary>
		private bool updateFlag = true;

		/// <summary>
		/// 标记线的绘制对象
		/// </summary>
		private Pen _markLinePen;

		/// <summary>
		/// 是否需要绘制标记线
		/// </summary>
		private bool needDrawMarkLine;

		private int _horizontalSeparatorSum = 10;

		private int _verticalSeparatorSum = 10;

		private AxisCollection _axisX = new AxisCollection();

		private AxisCollection _axisY = new AxisCollection();

		private SeriesCollection _series = new SeriesCollection();

		private Rectangle _border;

		private int _offsetX;

		private int _offsetY;

		private bool _horizontalGridVisible = true;

		private bool _verticalGridVisible = true;

		private bool _miniGridVisible = false;

		private DashStyle _miniGridDashStyle = DashStyle.Dot;

		private bool _legendVisible = true;

		private bool _zoomEnabled = true;

		private bool _allowDrag = true;

		private bool _markLineVisible = false;

		private Color _markLineColor = Color.FromArgb(80, 126, 211);

		private bool _selectPointEnabled = true;

		/// <summary>
		/// 颜色集合
		/// </summary>
		public static List<Color> Colors
		{
			get;
			set;
		}

		/// <summary>
		/// 颜色序号
		/// </summary>
		public static int ColorIndex
		{
			get;
			set;
		}

		/// <summary>
		/// 提示工具
		/// </summary>
		internal ToolTip MainToolTip
		{
			get;
			private set;
		}

		/// <summary>
		/// 图例容器
		/// </summary>
		internal FlowLayoutPanel LegendPanel
		{
			get;
			private set;
		}

		/// <summary>
		/// 横向分隔器个数
		/// </summary>
		[Category("HslChart")]
		[Description("横向分隔器个数。")]
		[DefaultValue(10)]
		public int HorizontalSeparatorSum
		{
			get
			{
				return _horizontalSeparatorSum;
			}
			set
			{
				_horizontalSeparatorSum = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 垂直分隔器个数
		/// </summary>
		[Category("HslChart")]
		[Description("垂直分隔器个数。")]
		[DefaultValue(10)]
		public int VerticalSeparatorSum
		{
			get
			{
				return _verticalSeparatorSum;
			}
			set
			{
				_verticalSeparatorSum = value;
				Invalidate();
			}
		}

		/// <summary>
		/// X轴集合
		/// </summary>
		[Category("HslChart")]
		[Description("X轴集合。")]
		[TypeConverter(typeof(CollectionConverter))]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public AxisCollection AxisX => _axisX;

		/// <summary>
		/// Y轴集合
		/// </summary>
		[Category("HslChart")]
		[Description("Y轴集合。")]
		[TypeConverter(typeof(CollectionConverter))]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public AxisCollection AxisY => _axisY;

		/// <summary>
		/// 数据串集合
		/// </summary>
		[Category("HslChart")]
		[Description("数据串集合。")]
		[TypeConverter(typeof(CollectionConverter))]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public SeriesCollection Series => _series;

		/// <summary>
		/// 绘图区域边界
		/// </summary>
		[Browsable(false)]
		public Rectangle Border => _border;

		/// <summary>
		/// 横向偏移量
		/// </summary>
		[Browsable(false)]
		public int OffsetX
		{
			get
			{
				return _offsetX;
			}
			set
			{
				_offsetX = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 垂直偏移量
		/// </summary>
		[Browsable(false)]
		public int OffsetY
		{
			get
			{
				return _offsetY;
			}
			set
			{
				_offsetY = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 显示/隐藏横向网格线
		/// </summary>
		[Category("HslChart")]
		[Description("显示/隐藏横向网格线。")]
		[DefaultValue(true)]
		public bool HorizontalGridVisible
		{
			get
			{
				return _horizontalGridVisible;
			}
			set
			{
				_horizontalGridVisible = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 显示/隐藏垂直网格线
		/// </summary>
		[Category("HslChart")]
		[Description("显示/隐藏垂直网格线。")]
		[DefaultValue(true)]
		public bool VerticalGridVisible
		{
			get
			{
				return _verticalGridVisible;
			}
			set
			{
				_verticalGridVisible = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 显示/隐藏小网格线
		/// </summary>
		[Category("HslChart")]
		[Description("显示/隐藏小网格线。")]
		[DefaultValue(false)]
		public bool MiniGridVisible
		{
			get
			{
				return _miniGridVisible;
			}
			set
			{
				_miniGridVisible = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 小网格线的样式
		/// </summary>
		[Category("HslChart")]
		[Description("小网格线的样式。")]
		[DefaultValue(DashStyle.Dot)]
		public DashStyle MiniGridDashStyle
		{
			get
			{
				return _miniGridDashStyle;
			}
			set
			{
				_miniGridDashStyle = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 显示/隐藏图例
		/// </summary>
		[Category("HslChart")]
		[Description("显示/隐藏图例。")]
		[DefaultValue(true)]
		public bool LegendVisible
		{
			get
			{
				return _legendVisible;
			}
			set
			{
				_legendVisible = value;
				LegendPanel.Visible = _legendVisible;
				Invalidate();
			}
		}

		/// <summary>
		/// 图例停靠位置
		/// </summary>
		/// <remarks>无法设置为Fill或None</remarks>
		[Category("HslChart")]
		[Description("图例停靠位置。")]
		[DefaultValue(DockStyle.Top)]
		public DockStyle LegendDock
		{
			get
			{
				return LegendPanel.Dock;
			}
			set
			{
				if (value != 0 && value != DockStyle.Fill)
				{
					if (value == DockStyle.Top || value == DockStyle.Bottom)
					{
						LegendPanel.FlowDirection = FlowDirection.LeftToRight;
					}
					else if (value == DockStyle.Left || value == DockStyle.Right)
					{
						LegendPanel.FlowDirection = FlowDirection.TopDown;
					}
					LegendPanel.Dock = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 图例字体
		/// </summary>
		[Category("HslChart")]
		[Description("图例字体。")]
		public Font LegendFont
		{
			get
			{
				return LegendPanel.Font;
			}
			set
			{
				LegendPanel.Font = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 缩放使能
		/// </summary>
		[Category("HslChart")]
		[Description("缩放使能。")]
		[DefaultValue(true)]
		public bool ZoomEnabled
		{
			get
			{
				return _zoomEnabled;
			}
			set
			{
				_zoomEnabled = value;
			}
		}

		/// <summary>
		/// 是否允许鼠标拖动
		/// </summary>
		[Category("HslChart")]
		[Description("是否允许鼠标拖动")]
		[DefaultValue(true)]
		public bool AllowDrag
		{
			get
			{
				return _allowDrag;
			}
			set
			{
				_allowDrag = value;
			}
		}

		/// <summary>
		/// 显示/隐藏标记线
		/// </summary>
		[Category("HslChart")]
		[Description("显示/隐藏标记线。")]
		[DefaultValue(false)]
		public bool MarkLineVisible
		{
			get
			{
				return _markLineVisible;
			}
			set
			{
				_markLineVisible = value;
			}
		}

		/// <summary>
		/// 标记线颜色
		/// </summary>
		[Category("HslChart")]
		[Description("标记线颜色。")]
		[DefaultValue(typeof(Color), "80, 126, 211")]
		public Color MarkLineColor
		{
			get
			{
				return _markLineColor;
			}
			set
			{
				_markLineColor = value;
				_markLinePen = new Pen(_markLineColor);
			}
		}

		/// <summary>
		/// 查找数据点使能
		/// </summary>
		[Category("HslChart")]
		[Description("查找数据点使能。")]
		[DefaultValue(true)]
		public bool SelectPointEnabled
		{
			get
			{
				return _selectPointEnabled;
			}
			set
			{
				_selectPointEnabled = value;
			}
		}

		/// <summary>
		/// 查找数据点的模式
		/// </summary>
		[Category("HslChart")]
		[Description("查找数据点的模式。")]
		[DefaultValue(SelectMode.Both)]
		public SelectMode SelectMode
		{
			get;
			set;
		} = SelectMode.Both;


		/// <summary>
		/// 使用X值查找模式时，X值所对应的X轴序号。
		/// </summary>
		[Browsable(false)]
		public int AxisXIndexForSelect
		{
			get;
			set;
		}

		/// <summary>
		/// 使用Y值查找模式时，Y值所对应的Y轴序号。
		/// </summary>
		[Browsable(false)]
		public int AxisYIndexForSelect
		{
			get;
			set;
		}

		[Bindable(false)]
		[Browsable(false)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public override Image BackgroundImage
		{
			get
			{
				return base.BackgroundImage;
			}
			set
			{
				base.BackgroundImage = value;
			}
		}

		[Bindable(false)]
		[Browsable(false)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public override ImageLayout BackgroundImageLayout
		{
			get
			{
				return base.BackgroundImageLayout;
			}
			set
			{
				base.BackgroundImageLayout = value;
			}
		}

		[Bindable(false)]
		[Browsable(false)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public override RightToLeft RightToLeft
		{
			get
			{
				return base.RightToLeft;
			}
			set
			{
				base.RightToLeft = value;
			}
		}

		/// <summary>
		/// 获取到数据点事件
		/// </summary>
		public event ChartPointEventHandler GotChartPoint;

		/// <summary>
		/// 静态构造函数
		/// </summary>
		static HslChart()
		{
			Colors = new List<Color>
			{
				Color.FromArgb(41, 127, 184),
				Color.FromArgb(230, 76, 60),
				Color.FromArgb(240, 195, 15),
				Color.FromArgb(26, 187, 155),
				Color.FromArgb(87, 213, 140),
				Color.FromArgb(154, 89, 181),
				Color.FromArgb(92, 109, 126),
				Color.FromArgb(22, 159, 132),
				Color.FromArgb(39, 173, 96),
				Color.FromArgb(92, 171, 225),
				Color.FromArgb(141, 68, 172),
				Color.FromArgb(229, 126, 34),
				Color.FromArgb(210, 84, 0),
				Color.FromArgb(191, 57, 43)
			};
		}

		/// <summary>
		/// 实例化一个ZChart对象
		/// </summary>
		public HslChart()
		{
			SetStyle(ControlStyles.OptimizedDoubleBuffer, value: true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, value: true);
			SetStyle(ControlStyles.UserPaint, value: true);
			BackColor = Color.White;
			Font = new Font("微软雅黑", 12f);
			ForeColor = Color.FromArgb(51, 51, 51);
			base.Padding = new Padding(6);
			base.Size = new Size(400, 300);
			base.TabStop = false;
			_axisX.Chart = this;
			_axisX.Type = AxisType.X;
			_axisY.Chart = this;
			_axisY.Type = AxisType.Y;
			_series.Chart = this;
			_markLinePen = new Pen(_markLineColor);
			MainToolTip = new ToolTip();
			LegendPanel = new FlowLayoutPanel
			{
				AutoSize = true,
				Dock = DockStyle.Top
			};
			base.Controls.Add(LegendPanel);
			base.PaddingChanged += delegate
			{
				Invalidate();
			};
		}

		private void OnGotChartPoint(ChartPointEventArgs e)
		{
			this.GotChartPoint?.Invoke(this, e);
		}

		protected override void OnCreateControl()
		{
			base.OnCreateControl();
			InitializeChart();
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);
			if (updateFlag)
			{
				Stopwatch debugWatch = new Stopwatch();
				debugWatch.Start();
				Graphics g = e.Graphics;
				g.Clear(BackColor);
				UpdateAxisRange();
				UpdateChartBorder(g, base.Size);
				UpdateAxisSize();
				g.SmoothingMode = SmoothingMode.HighQuality;
				DrawFrame(g);
				DrawAxis(g);
				g.Clip = new Region(_border);
				DrawSeries(g);
				DrawMarkLine(g);
				debugWatch.Stop();
				Debug.WriteLine($"It took {debugWatch.ElapsedMilliseconds} milliseconds to redraw.");
			}
		}

		protected override void OnSizeChanged(EventArgs e)
		{
			base.OnSizeChanged(e);
			Invalidate();
		}

		protected override void OnMouseDown(MouseEventArgs e)
		{
			base.OnMouseDown(e);
			if (_allowDrag && e.Button == MouseButtons.Left)
			{
				dragLocation = e.Location;
				isDraging = true;
				Cursor = Cursors.Hand;
			}
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			base.OnMouseMove(e);
			bool needPaint = false;
			if (_allowDrag && isDraging)
			{
				int offsetX = e.X - dragLocation.X;
				int offsetY = e.Y - dragLocation.Y;
				dragLocation = e.Location;
				if (offsetX != 0 || offsetY != 0)
				{
					_offsetX += offsetX;
					_offsetY += offsetY;
					needPaint = true;
				}
			}
			if (_markLineVisible)
			{
				if (_border.Contains(e.Location))
				{
					if (markLineLocation != e.Location)
					{
						markLineLocation = e.Location;
						needDrawMarkLine = true;
						needPaint = true;
					}
				}
				else if (needDrawMarkLine)
				{
					needDrawMarkLine = false;
					needPaint = true;
				}
			}
			if (needPaint)
			{
				Invalidate();
			}
		}

		protected override void OnMouseUp(MouseEventArgs e)
		{
			base.OnMouseUp(e);
			if (_selectPointEnabled && _border.Contains(e.Location) && e.Button == MouseButtons.Left)
			{
				SelectPoints(e.Location);
			}
			if (_allowDrag && e.Button == MouseButtons.Left)
			{
				isDraging = false;
				Cursor = Cursors.Default;
			}
		}

		protected override void OnMouseWheel(MouseEventArgs e)
		{
			base.OnMouseWheel(e);
			if (_zoomEnabled && _border.Contains(e.Location))
			{
				if (e.Delta > 0 && zoomTimes > -1.95)
				{
					zoomTimes -= 0.05;
				}
				else if (e.Delta < 0 && zoomTimes < 0.45)
				{
					zoomTimes += 0.05;
				}
				zoomTimes = Math.Round(zoomTimes, 2);
				Invalidate();
			}
		}

		protected override void OnMouseLeave(EventArgs e)
		{
			base.OnMouseLeave(e);
			MainToolTip.SetToolTip(this, null);
			if (needDrawMarkLine)
			{
				needDrawMarkLine = false;
				Invalidate();
			}
		}

		/// <summary>
		/// 初始化图表，为集合属性的元素设置引用。
		/// </summary>
		private void InitializeChart()
		{
			foreach (SeriesBase s in _series)
			{
				s.Chart = this;
				s.Points.Chart = this;
				s.Points.Series = s;
				foreach (ChartPoint cp in s.Points)
				{
					cp.Chart = this;
					cp.Series = s;
				}
			}
			foreach (Axis axis2 in _axisX)
			{
				axis2.Chart = this;
				axis2.Type = AxisType.X;
			}
			foreach (Axis axis in _axisY)
			{
				axis.Chart = this;
				axis.Type = AxisType.Y;
			}
		}

		/// <summary>
		/// 更新坐标轴数据范围
		/// </summary>
		private void UpdateAxisRange()
		{
			foreach (Axis x2 in _axisX)
			{
				x2.ResetRange();
			}
			foreach (Axis y2 in _axisY)
			{
				y2.ResetRange();
			}
			foreach (SeriesBase s in _series)
			{
				if (s.ScalesXAt >= 0 && s.ScalesXAt < _axisX.Count)
				{
					Axis axisX = _axisX[s.ScalesXAt];
					axisX.UpdateRange(s, AxisType.X, _verticalSeparatorSum);
				}
				if (s.ScalesYAt >= 0 && s.ScalesYAt < _axisY.Count)
				{
					Axis axisY = _axisY[s.ScalesYAt];
					axisY.UpdateRange(s, AxisType.Y, _horizontalSeparatorSum);
				}
			}
			foreach (Axis x in _axisX)
			{
				x.UpdateZoom(zoomTimes);
			}
			foreach (Axis y in _axisY)
			{
				y.UpdateZoom(zoomTimes);
			}
		}

		/// <summary>
		/// 更新绘图区域边界
		/// </summary>
		/// <param name="g">绘图对象</param>
		/// <param name="size">控件尺寸</param>
		private void UpdateChartBorder(Graphics g, Size size)
		{
			float top = 0f;
			float bottom = 0f;
			float left = 0f;
			float right = 0f;
			foreach (Axis axis in _axisX)
			{
				axis.UpdateLabel(_verticalSeparatorSum);
				axis.UpdateSize1(g, Font);
				if (axis.Position == AxisPosition.LeftBottom)
				{
					bottom += axis.Height;
				}
				else
				{
					top += axis.Height;
				}
			}
			foreach (Axis axis2 in _axisY)
			{
				axis2.UpdateLabel(_horizontalSeparatorSum);
				axis2.UpdateSize1(g, Font);
				if (axis2.Position == AxisPosition.LeftBottom)
				{
					left += axis2.Width;
				}
				else
				{
					right += axis2.Width;
				}
			}
			top += (float)base.Padding.Top;
			bottom += (float)base.Padding.Bottom;
			left += (float)base.Padding.Left;
			right += (float)base.Padding.Right;
			int x = (int)left;
			int y = (int)top;
			int width = (int)((float)size.Width - left - right);
			int height = (int)((float)size.Height - top - bottom);
			if (LegendPanel.Visible)
			{
				switch (LegendPanel.Dock)
				{
				case DockStyle.Top:
					LegendPanel.Padding = new Padding(x + 3, base.Padding.Top, (int)right + 3, 0);
					y += LegendPanel.Height + 3;
					height -= LegendPanel.Height + 3;
					break;
				case DockStyle.Bottom:
					LegendPanel.Padding = new Padding(x + 3, 0, (int)right + 3, base.Padding.Bottom);
					height -= LegendPanel.Height + 3;
					break;
				case DockStyle.Left:
					LegendPanel.Padding = new Padding(base.Padding.Left, y + 3, 0, (int)bottom + 3);
					x += LegendPanel.Width + 3;
					width -= LegendPanel.Width + 3;
					break;
				case DockStyle.Right:
					LegendPanel.Padding = new Padding(0, y + 3, base.Padding.Right, (int)bottom + 3);
					width -= LegendPanel.Width + 3;
					break;
				}
			}
			_border = new Rectangle(x, y, width, height);
		}

		/// <summary>
		/// 更新坐标轴尺寸信息
		/// </summary>
		private void UpdateAxisSize()
		{
			foreach (Axis axis2 in _axisX)
			{
				axis2.UpdateSize2(_border, _verticalSeparatorSum);
				axis2.UpdateOffset(_verticalSeparatorSum, _offsetX);
			}
			foreach (Axis axis in _axisY)
			{
				axis.UpdateSize2(_border, _horizontalSeparatorSum);
				axis.UpdateOffset(_horizontalSeparatorSum, -_offsetY);
			}
		}

		/// <summary>
		/// 绘制网格框架
		/// </summary>
		/// <param name="g">绘图对象</param>
		internal void DrawFrame(Graphics g)
		{
			Pen p1 = new Pen(Color.FromArgb(111, ForeColor));
			Pen p2 = new Pen(Color.FromArgb(58, ForeColor));
			Pen p3 = new Pen(Color.FromArgb(53, ForeColor))
			{
				DashStyle = _miniGridDashStyle
			};
			g.DrawRectangle(p1, _border);
			p1.Dispose();
			if (_horizontalGridVisible)
			{
				int x2 = _border.Left;
				int x3 = _border.Right;
				float axisLenght2 = _border.Height;
				float step2 = axisLenght2 / (float)_horizontalSeparatorSum;
				float offset2 = (float)_offsetY % step2;
				float y = (float)_border.Top + offset2;
				for (int l = 0; l < _horizontalSeparatorSum + 1; l++)
				{
					if (_border.Contains(_border.Left, (int)y))
					{
						g.DrawLine(p2, x2, y, x3, y);
					}
					y += step2;
				}
				if (_miniGridVisible)
				{
					float miniStep2 = step2 / 5f;
					offset2 = (float)_offsetY % miniStep2;
					y = (float)_border.Top + offset2;
					for (int k = 0; k < _horizontalSeparatorSum * 5 + 1; k++)
					{
						if (_border.Contains(_border.Left, (int)y))
						{
							g.DrawLine(p3, x2, y, x3, y);
						}
						y += miniStep2;
					}
				}
			}
			if (_verticalGridVisible)
			{
				int y2 = _border.Top;
				int y3 = _border.Bottom;
				float axisLenght = _border.Width;
				float step = axisLenght / (float)_verticalSeparatorSum;
				float offset = (float)_offsetX % step;
				float x = (float)_border.Left + offset;
				for (int j = 0; j < _verticalSeparatorSum + 1; j++)
				{
					if (_border.Contains((int)x, _border.Top))
					{
						g.DrawLine(p2, x, y2, x, y3);
					}
					x += step;
				}
				if (_miniGridVisible)
				{
					float miniStep = step / 5f;
					offset = (float)_offsetX % miniStep;
					x = (float)_border.Left + offset;
					for (int i = 0; i < _verticalSeparatorSum * 5 + 1; i++)
					{
						if (_border.Contains((int)x, _border.Top))
						{
							g.DrawLine(p3, x, y2, x, y3);
						}
						x += miniStep;
					}
				}
			}
			p2.Dispose();
			p3.Dispose();
		}

		/// <summary>
		/// 绘制坐标轴
		/// </summary>
		/// <param name="g">绘图对象</param>
		private void DrawAxis(Graphics g)
		{
			DrawAxisX(g);
			DrawAxisY(g);
		}

		/// <summary>
		/// 绘制X轴
		/// </summary>
		/// <param name="g">绘图对象</param>
		private void DrawAxisX(Graphics g)
		{
			float top = base.Padding.Top;
			float bottom = 0f;
			if (LegendPanel.Visible)
			{
				switch (LegendPanel.Dock)
				{
				case DockStyle.Top:
					top += (float)LegendPanel.Height + 3f;
					break;
				}
			}
			foreach (Axis axis in _axisX)
			{
				axis.DrawAxisX(g, Font, _border, _offsetX, ref top, ref bottom);
			}
		}

		/// <summary>
		/// 绘制Y轴
		/// </summary>
		/// <param name="g">绘图对象</param>
		private void DrawAxisY(Graphics g)
		{
			float left = base.Padding.Left;
			float right = 0f;
			if (LegendPanel.Visible)
			{
				switch (LegendPanel.Dock)
				{
				case DockStyle.Left:
					left += (float)LegendPanel.Width + 3f;
					break;
				}
			}
			foreach (Axis axis in _axisY)
			{
				axis.DrawAxisY(g, Font, _border, _offsetY, ref left, ref right);
			}
		}

		/// <summary>
		/// 绘制数据串
		/// </summary>
		/// <param name="g">绘图对象</param>
		private void DrawSeries(Graphics g)
		{
			foreach (SeriesBase s2 in _series)
			{
				if (s2.Visible)
				{
					s2.Draw(g);
				}
			}
			List<ColumnSeries> lstColumnSeries = new List<ColumnSeries>();
			foreach (SeriesBase s in _series)
			{
				ColumnSeries columnSeries = s as ColumnSeries;
				if (columnSeries != null)
				{
					lstColumnSeries.Add(columnSeries);
				}
			}
			if (lstColumnSeries != null && lstColumnSeries.Count() > 0)
			{
				ColumnSeries.Draw(g, _border, _verticalSeparatorSum, lstColumnSeries.ToArray());
			}
		}

		/// <summary>
		/// 绘制标记线
		/// </summary>
		/// <param name="g">绘图对象</param>
		private void DrawMarkLine(Graphics g)
		{
			if (needDrawMarkLine && !isDraging)
			{
				g.DrawLine(_markLinePen, markLineLocation.X, _border.Top, markLineLocation.X, _border.Bottom);
			}
		}

		/// <summary>
		/// 查找数据点
		/// </summary>
		/// <param name="location">坐标</param>
		private void SelectPoints(Point location)
		{
			Stopwatch debugWatch = new Stopwatch();
			debugWatch.Start();
			ChartPoint[] pts = null;
			string content = null;
			switch (SelectMode)
			{
			case SelectMode.Both:
				pts = SelectPointsByLocation(location, 4);
				if (pts != null)
				{
					content = GetPointsContent1(pts);
				}
				break;
			case SelectMode.X:
				pts = SelectPointsByX(AxisXIndexForSelect, location.X, 4);
				if (pts != null)
				{
					content = GetPointsContent2(pts);
				}
				break;
			case SelectMode.Y:
				pts = SelectPointsByY(AxisYIndexForSelect, location.Y, 4);
				if (pts != null)
				{
					content = GetPointsContent3(pts);
				}
				break;
			}
			if (pts != null)
			{
				ChartPointEventArgs cpEventArgs = new ChartPointEventArgs(pts, content);
				OnGotChartPoint(cpEventArgs);
				MainToolTip.SetToolTip(this, cpEventArgs.Content);
			}
			debugWatch.Stop();
			Debug.WriteLine($"It took {debugWatch.ElapsedMilliseconds} to find the data.");
		}

		/// <summary>
		/// 获取数据点在图表上的坐标
		/// </summary>
		/// <param name="scalesXAt">附着的X轴序号</param>
		/// <param name="scalesYAt">附着的Y轴序号</param>
		/// <param name="cp">数据点</param>
		/// <returns>坐标</returns>
		public PointF GetPointLocation(int scalesXAt, int scalesYAt, ChartPoint cp)
		{
			return new PointF(CountLeft(scalesXAt, cp.X), CountTop(scalesYAt, cp.Y));
		}

		/// <summary>
		/// 计算数据点与图表左边缘的距离
		/// </summary>
		/// <param name="scalesXAt">附着的X轴序号</param>
		/// <param name="xValue">数据值X</param>
		/// <returns>距离</returns>
		public float CountLeft(int scalesXAt, double xValue)
		{
			double axisXLenght = _border.Width;
			double unitX = axisXLenght / _axisX[scalesXAt].Range;
			double x = (xValue - _axisX[scalesXAt].MinValue) * unitX;
			if (_axisX[scalesXAt].IsReverse)
			{
				x = axisXLenght - x;
			}
			x += (double)_border.Left;
			return Convert.ToSingle(x);
		}

		/// <summary>
		/// 计算数据点与图表上边缘的距离
		/// </summary>
		/// <param name="scalesYAt">附着的Y轴序号</param>
		/// <param name="yValue">数据值Y</param>
		/// <returns>距离</returns>
		public float CountTop(int scalesYAt, double yValue)
		{
			double axisYLenght = _border.Height;
			double unitY = axisYLenght / _axisY[scalesYAt].Range;
			double y = (yValue - _axisY[scalesYAt].MinValue) * unitY;
			if (!_axisY[scalesYAt].IsReverse)
			{
				y = axisYLenght - y;
			}
			y += (double)_border.Top;
			return Convert.ToSingle(y);
		}

		/// <summary>
		/// 计算数据值X
		/// </summary>
		/// <param name="scalesXAt">附着的X轴序号</param>
		/// <param name="xLocation">图表的X坐标</param>
		/// <returns>数据值X</returns>
		public double CountValueX(int scalesXAt, double xLocation)
		{
			double axisXLenght = _border.Width;
			double unitX = _axisX[scalesXAt].Range / axisXLenght;
			double x = (xLocation - (double)_border.Left) * unitX;
			if (_axisX[scalesXAt].IsReverse)
			{
				x = _axisX[scalesXAt].Range - x;
			}
			return x - Math.Abs(_axisX[scalesXAt].MinValue);
		}

		/// <summary>
		/// 计算数据值Y
		/// </summary>
		/// <param name="scalesYAt">附着的Y轴序号</param>
		/// <param name="yLocation">图表的Y坐标</param>
		/// <returns>数据值Y</returns>
		public double CountValueY(int scalesYAt, double yLocation)
		{
			double axisYLenght = _border.Height;
			double unitY = _axisY[scalesYAt].Range / axisYLenght;
			double y = (yLocation - (double)_border.Top) * unitY;
			if (!_axisY[scalesYAt].IsReverse)
			{
				y = _axisY[scalesYAt].Range - y;
			}
			return y - Math.Abs(_axisY[scalesYAt].MinValue);
		}

		/// <summary>
		/// 获取鼠标位置的数据值
		/// </summary>
		/// <param name="mouseLocation">鼠标位置</param>
		/// <returns>数据值</returns>
		public string GetMouseValueStr(Point mouseLocation)
		{
			string str = "";
			int axisXSum = _axisX.Count;
			if (axisXSum > 0)
			{
				for (int j = 0; j < axisXSum; j++)
				{
					if (!_axisX[j].IsCustomLabels)
					{
						double valX = CountValueX(j, mouseLocation.X);
						str += $"{_axisX[j].Title}:{Math.Round(valX, 2)}\r\n";
					}
				}
			}
			int axisYSum = _axisY.Count;
			if (axisYSum > 0)
			{
				for (int i = 0; i < axisYSum; i++)
				{
					if (!_axisY[i].IsCustomLabels)
					{
						double valY = CountValueY(i, mouseLocation.Y);
						str += $"{_axisY[i].Title}:{Math.Round(valY, 2)}\r\n";
					}
				}
			}
			return str;
		}

		/// <summary>
		/// 支持呈现到指定的位图
		/// </summary>
		/// <param name="bitmap">要绘制到的位图</param>
		/// <returns>位图</returns>
		public void DrawToBitmap(Bitmap bitmap)
		{
			if (bitmap != null)
			{
				Size currentSize = base.Size;
				Point currentLocation = base.Location;
				DockStyle currentDock = Dock;
				Dock = DockStyle.None;
				base.Size = bitmap.Size;
				DrawToBitmap(bitmap, base.ClientRectangle);
				base.Size = currentSize;
				base.Location = currentLocation;
				Dock = currentDock;
			}
		}

		/// <summary>
		/// 设置图表偏移量
		/// </summary>
		/// <param name="offsetX">X轴偏移量</param>
		/// <param name="offsetY">Y轴偏移量</param>
		public void SetOffset(int offsetX, int offsetY)
		{
			_offsetX = offsetX;
			_offsetY = offsetY;
			Invalidate();
		}

		/// <summary>
		/// 设置图表缩放倍数
		/// </summary>
		/// <remarks>设置正值放大，设置负值缩小，范围(-2~+0.5)</remarks>
		/// <param name="times">缩放倍数</param>
		public void SetZoomTimes(double times)
		{
			if (times < -2.0)
			{
				zoomTimes = -2.0;
			}
			else if (times > 0.5)
			{
				zoomTimes = 0.5;
			}
			else
			{
				zoomTimes = times;
			}
			zoomTimes = Math.Round(zoomTimes, 2);
			Invalidate();
		}

		/// <summary>
		/// 开始更新，在更新大量内容前调用。
		/// </summary>
		/// <remarks>更新结束后一定要调用<see cref="M:HslControls.HslChart.EndUpdate" />方法，否则图表将不再绘制。</remarks>
		public void BeginUpdate()
		{
			updateFlag = false;
		}

		/// <summary>
		/// 结束更新，在调用完<see cref="M:HslControls.HslChart.BeginUpdate" />方法之后调用。
		/// </summary>
		public void EndUpdate()
		{
			updateFlag = true;
			Invalidate();
		}

		/// <summary>
		/// 查找数据点
		/// </summary>
		/// <param name="location">坐标</param>
		/// <param name="range">范围</param>
		/// <returns>数据点数组</returns>
		public ChartPoint[] SelectPointsByLocation(Point location, int range)
		{
			List<ChartPoint> lst = new List<ChartPoint>();
			foreach (SeriesBase s in Series)
			{
				ChartPoint pt = s.Select(location.X, location.Y, range);
				if (pt != null)
				{
					lst.Add(pt);
				}
			}
			if (lst.Count > 0)
			{
				return lst.ToArray();
			}
			return null;
		}

		/// <summary>
		/// 查找数据点
		/// </summary>
		/// <param name="indexOfAxisX">X坐标轴序号</param>
		/// <param name="x">图表上的X坐标</param>
		/// <param name="range">范围</param>
		/// <returns>数据点数组</returns>
		public ChartPoint[] SelectPointsByX(int indexOfAxisX, int x, int range)
		{
			List<ChartPoint> lst = new List<ChartPoint>();
			foreach (SeriesBase s in _series)
			{
				if (s.ScalesXAt != indexOfAxisX)
				{
					continue;
				}
				ChartPoint cp = s.SelectByX(x, range);
				if (cp != null)
				{
					if (lst.Count == 0)
					{
						lst.Add(cp);
					}
					else if (cp.X == lst[0].X)
					{
						lst.Add(cp);
					}
				}
			}
			if (lst.Count > 0)
			{
				return lst.ToArray();
			}
			return null;
		}

		/// <summary>
		/// 查找数据点
		/// </summary>
		/// <param name="indexOfAxisY">Y坐标轴序号</param>
		/// <param name="y">图表上的Y坐标</param>
		/// <param name="range">范围</param>
		/// <returns>数据点数组</returns>
		public ChartPoint[] SelectPointsByY(int indexOfAxisY, int y, int range)
		{
			List<ChartPoint> lst = new List<ChartPoint>();
			foreach (SeriesBase s in _series)
			{
				if (s.ScalesYAt != indexOfAxisY)
				{
					continue;
				}
				ChartPoint cp = s.SelectByY(y, range);
				if (cp != null)
				{
					if (lst.Count == 0)
					{
						lst.Add(cp);
					}
					else if (cp.Y == lst[0].Y)
					{
						lst.Add(cp);
					}
				}
			}
			if (lst.Count > 0)
			{
				return lst.ToArray();
			}
			return null;
		}

		/// <summary>
		/// 获取数据点内容
		/// </summary>
		/// <param name="pts">数据点数组</param>
		/// <returns>数据点内容</returns>
		public string GetPointsContent1(ChartPoint[] pts)
		{
			string caption = "";
			foreach (ChartPoint pt in pts)
			{
				if (!string.IsNullOrEmpty(caption))
				{
					caption += "\r";
				}
				caption = caption + pt.Series.Title + "(" + pt.GetLabelFromAxisX() + " , " + pt.GetLabelFromAxisY() + ")";
			}
			return caption;
		}

		/// <summary>
		/// 获取数据点内容
		/// </summary>
		/// <param name="pts">数据点数组</param>
		/// <returns>数据点内容</returns>
		public string GetPointsContent2(ChartPoint[] pts)
		{
			string caption = pts[0].GetLabelFromAxisX() ?? "";
			foreach (ChartPoint pt in pts)
			{
				caption = caption + "\r" + pt.Series.Title + " : " + pt.GetLabelFromAxisY();
			}
			return caption;
		}

		/// <summary>
		/// 获取数据点内容
		/// </summary>
		/// <param name="pts">数据点数组</param>
		/// <returns>数据点内容</returns>
		public string GetPointsContent3(ChartPoint[] pts)
		{
			string caption = pts[0].GetLabelFromAxisY() ?? "";
			foreach (ChartPoint pt in pts)
			{
				caption = caption + "\r" + pt.Series.Title + " : " + pt.GetLabelFromAxisX();
			}
			return caption;
		}

		/// <summary>
		/// 设置提示文本
		/// </summary>
		/// <param name="caption">提示文本</param>
		public void SetToolTip(string caption)
		{
			MainToolTip.SetToolTip(this, caption);
		}

		[Bindable(false)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public override void ResetRightToLeft()
		{
			base.ResetRightToLeft();
		}
	}
}
